package com.ecoolex.chinadutyfree.retailer.core.manager;

import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.ecoolex.chinadutyfree.retailer.core.dao.CouponDAO;
import com.ecoolex.chinadutyfree.retailer.entity.Coupon;
import com.ecoolex.chinadutyfree.retailer.entity.Coupon.Column;
import com.ecoolex.chinadutyfree.retailer.entity.CouponClass;
import com.ecoolex.chinadutyfree.retailer.entity.CouponClassExpireStrategy;
import com.ecoolex.chinadutyfree.retailer.entity.CouponExample;
import com.ecoolex.chinadutyfree.retailer.entity.CouponExample.Criteria;
import com.ecoolex.chinadutyfree.retailer.entity.DirectMailGoodsOrder;
import com.ecoolex.chinadutyfree.retailer.entity.DirectMailGoodsOrderReceiver;
import com.ecoolex.chinadutyfree.retailer.enums.CouponClassExpiryStrategy;
import com.ecoolex.chinadutyfree.retailer.enums.CouponClassType;
import com.ecoolex.chinadutyfree.retailer.enums.CouponStatus;
import com.ecoolex.chinadutyfree.retailer.pojo.QueryCouponDTO;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.exception.BizException;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.pojo.Sortings;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.framework.common.util.RandomUtil;

@Service
public class CouponManager {
	
    @Autowired
    private CouponDAO dao;
    
    @Autowired
    private CouponClassManager couponClassManager;
    
    @Autowired
    private CouponClassExpireStrategyManager couponClassExpireStrategyManager;
    
    @Autowired
    private CouponVerifyingConsumptionManager consumptionManager;
    
    @Autowired
    private DirectMailGoodsOrderManager orderManager;
    
    @Autowired
    private DirectMailGoodsOrderReceiverManager receiverManager;
    
    public Coupon getByUserIdAndCouponClassId(Integer userId, Integer couponClassId) {
    	CouponExample example = new CouponExample();
    	Criteria criteria = example.createCriteria();
    	criteria.andUserIdEqualTo(userId)
    			.andCouponClassIdEqualTo(couponClassId)
    			.andStatusEqualTo(CouponStatus.UNUSED.real())
    			.andDeletedEqualTo(Coupon.NOT_DELETED);
		return dao.selectOneByExample(example);
	}
    
    public Pagination<Coupon> couponList(Integer userId, Page page) {
    	List<Integer> list = new ArrayList<Integer>();
    	list.add(CouponStatus.USED.real());
    	list.add(CouponStatus.INVALID.real());
    	CouponExample example = new CouponExample();
    	Criteria criteria = example.createCriteria();
    	criteria.andUserIdEqualTo(userId).andDeletedEqualTo(Coupon.NOT_DELETED)
    	.andStatusNotIn(list);
    	example.setOffset(page.getFirstIndex());
    	example.setRows(page.getPageSize());
    	example.orderBy(Column.endEffectiveTime.desc());
		return Pagination.create(page, 
			dao.countByExample(example),
			() -> dao.selectByExample(example));
	}
    
    public Pagination<Coupon> couponList(QueryCouponDTO query, Sorting[] sorts, Page page) {
		return Pagination.create(page, 
			dao.countByName(query),
			() -> dao.queryByName(query, Sortings.builder(sorts).toSql(), page));
	}
    
    /**
     * 用户领取优惠券
     * @param couponClassId
     * @param userId
     * @param createUser
     * @return
     */
    public Coupon receiveCoupon(Integer couponClassId, Integer userId, String createUser) {
    	boolean falg = couponClassManager.addReceiveNumber(couponClassId, createUser);
    	if(falg) {
    		CouponClass couponClass = couponClassManager.getCouponClassById(couponClassId);
    		CouponClassExpireStrategy expireStrategy = couponClassExpireStrategyManager.getByCouponClassId(couponClassId);
    		Coupon coupon = new Coupon();
    		coupon.setCurrencyType(couponClass.getCurrencyType());
    		coupon.setCouponClassId(couponClassId);
    		coupon.setCouponCode(code());
    		coupon.setStatus(CouponStatus.UNUSED.real());
    		coupon.setUserId(userId);
    		coupon.setStartEffectiveTime(expireStrategy.getAbsoluteStartTime());
    		coupon.setEndEffectiveTime(expireStrategy.getAbsoluteEndTime());
    		coupon.setDeleted(Coupon.NOT_DELETED);
			coupon.setCreateUser(createUser);
    		coupon.setCreateTime(Date.from(Instant.now()));
    		coupon.setUpdateUser(createUser);
    		coupon.setUpdateTime(Date.from(Instant.now()));
    		dao.insert(coupon);
    		return coupon;
    	}else {
    		throw new BizException("库存不足");
    	}
	}
    
    /**
     * 用户提交订单锁券
     * @param couponId
     * @param updateUser
     * @return
     */
    public Coupon lockCoupon(Integer orderId,Integer couponId,String updateUser) {
    	Coupon coupon = getCouponById(couponId);
    	BizAssert.isTrue(Check.notNull(coupon),ResultCode.VERIFY.build(10), "商户优惠券不存在或不可用");
    	DirectMailGoodsOrder order = orderManager.getById(orderId);
    	Boolean result = verifyCoupon(order.getCreateTime(),order.getTotalPrice(),couponId);
    	BizAssert.isTrue(result, ResultCode.VERIFY.build(11),"优惠券不可用");
    	coupon.setStatus(CouponStatus.USED.real());
    	coupon.setUpdateUser(updateUser);
    	coupon.setUpdateTime(Date.from(Instant.now()));
    	dao.updateByPrimaryKeySelective(coupon, Column.status,Column.updateUser,Column.updateTime);
    	return coupon;
    }
    
    //校验优惠券
    public Boolean verifyCoupon(Date createTime,BigDecimal realPrice,Integer couponId) {
    	Coupon coupon = getCouponById(couponId);
    	if(Check.isNull(coupon)) {
    		return false;
    	}
    	CouponClass couponClass = couponClassManager.getCouponClassById(coupon.getCouponClassId());
    	CouponClassExpireStrategy expireStrategy = couponClassExpireStrategyManager.getByCouponClassId(couponClass.getCouponClassId());
    	Boolean flag1 = true;
    	Boolean flag2 = true;
    	//绝对有效期
    	if(CouponClassExpiryStrategy.ABSOLUTE_EXPIRY.equal(expireStrategy.getExpiryStrategy())) {
    		flag1 = Check.isRangeWithin(createTime, expireStrategy.getAbsoluteStartTime(), expireStrategy.getAbsoluteEndTime());
    	}
    	//满减券
    	if(CouponClassType.FULL_REDUCTION.equal(couponClass.getType())) {
    		flag2 = Check.isGreatThanEqual(realPrice, couponClass.getThresholdPrice());
    	}
    	if(flag1 && flag2) {
    		return true;
    	}else {
    		return false;
    	}
    	
    }
    
    /**
     * 用户取消或自动取消订单释放券
     * @param couponId
     * @param updateUser
     * @return
     */
    public Coupon releaseCoupon(Integer couponId,String updateUser) {
    	Coupon coupon = getUsedCouponById(couponId);
		BizAssert.isTrue(Check.notNull(coupon),ResultCode.VERIFY.build(10), "商户优惠券不存在");
		coupon.setStatus(CouponStatus.UNUSED.real());
		coupon.setUpdateUser(updateUser);
    	coupon.setUpdateTime(Date.from(Instant.now()));
    	dao.updateByPrimaryKeySelective(coupon, Column.status,Column.updateUser,Column.updateTime);
		return coupon;
    }
    
    /**
     * 核销商户优惠券
     * @param orderNo
     * @param couponId
     * @param createUser
     */
    public Coupon verifyCoupon(Integer orderId,Integer couponId,String createUser) {
    	DirectMailGoodsOrderReceiver receiver = receiverManager.getByOrderId(orderId);
    	Coupon coupon = getUsedCouponById(couponId);
		BizAssert.isTrue(Check.notNull(coupon),ResultCode.VERIFY.build(10), "优惠券不存在");
		coupon.setReceiverPhone(receiver.getPhone());
		coupon.setStatus(CouponStatus.USED.real());
		coupon.setUseTime(Date.from(Instant.now()));
		coupon.setUpdateUser(createUser);
		coupon.setUpdateTime(Date.from(Instant.now()));
		dao.updateByPrimaryKeySelective(coupon,Column.status, Column.useTime,Column.updateUser,Column.updateTime);
		//创建核销记录
		DirectMailGoodsOrder order = orderManager.getById(orderId);
		consumptionManager.create(coupon, order.getOrderNo(),order.getRealPrice(), createUser);
		return coupon;
    }
    
    /**
     * 处理过期券
     * @param coupon
     * @param updateUser
     */
    public void expireCoupon(Coupon coupon,String updateUser) {
    	coupon.setStatus(CouponStatus.EXPIRED.real());
    	coupon.setUpdateUser(updateUser);
    	coupon.setUpdateTime(Date.from(Instant.now()));
    	dao.updateByPrimaryKeySelective(coupon, Column.status,Column.updateUser,Column.updateTime);
    }
    
    public List<Coupon> getExpireCoupon(Date now,Integer size){
    	CouponExample example = new CouponExample();
    	Criteria criteria = example.createCriteria();
    	criteria.andStatusEqualTo(CouponStatus.UNUSED.real())
    	.andEndEffectiveTimeLessThanOrEqualTo(now)
    	.andDeletedEqualTo(Coupon.NOT_DELETED);
    	example.orderBy(Column.endEffectiveTime.asc());
    	example.limit(size);
    	return dao.selectByExample(example);
    }
    
    private String code() {
    	String code = RandomUtil.randomInt(15);
    	Coupon old = getByCouponCode(code);
		if(Check.notNull(old)) {
			return code();
		}
		return code;
    }
    
    public Coupon getByCouponCode(String couponCode){
    	CouponExample example = new CouponExample();
    	Criteria criteria = example.createCriteria();
    	criteria.andCouponCodeEqualTo(couponCode).andDeletedEqualTo(Coupon.NOT_DELETED);
    	return dao.selectOneByExample(example);
    }
    
    public void deleteAllByCouponClassId(Integer couponClassId, String updateUser) {
		// 修改条件
		CouponExample example = new CouponExample();
		example.createCriteria().andCouponClassIdEqualTo(couponClassId).andDeletedEqualTo(Coupon.NOT_DELETED);

		// 修改内容
		Coupon record = new Coupon();
		record.setDeleted(Coupon.IS_DELETED);
		record.setUpdateUser(updateUser);
		record.setUpdateTime(Date.from(Instant.now()));

		dao.updateByExampleSelective(record, example, Column.deleted, Column.updateUser, Column.updateTime);
	}

	public Coupon getCouponById(Integer couponId){
		CouponExample example = new CouponExample();
		CouponExample.Criteria criteria = example.createCriteria();
		criteria.andDeletedEqualTo(Coupon.NOT_DELETED);
		criteria.andStatusEqualTo(CouponStatus.UNUSED.real());
		criteria.andCouponIdEqualTo(couponId);
		return dao.selectOneByExample(example);
	}
	
	public Coupon getUsedCouponById(Integer couponId) {
		CouponExample example = new CouponExample();
		CouponExample.Criteria criteria = example.createCriteria();
		criteria.andDeletedEqualTo(Coupon.NOT_DELETED);
		criteria.andStatusEqualTo(CouponStatus.USED.real());
		criteria.andCouponIdEqualTo(couponId);
		return dao.selectOneByExample(example);
	}
}